package com.kalvan.web.servlet.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * 防注入攻击
 *
 * @author kalvan
 */
@Slf4j
public class ParameterRequestInterceptor extends HandlerInterceptorAdapter {

    private Map<String, String[]> params = new HashMap<String, String[]>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 将参数表，赋予给当前的Map以便于持有request中的参数
        Map<String, String[]> requestMap = request.getParameterMap();
        // log.debug("转化前参数：{}", JSON.toJSONString(requestMap));
        this.params.putAll(requestMap);
        this.modifyParameterValues();
        // log.debug("转化后参数：{}", JSON.toJSONString(params));
        for (Map.Entry<String, String[]> entry : requestMap.entrySet()) {
            String[] values = entry.getValue();
            for (String value : values) {
                // sql注入直接拦截
                if (StringUtils.isNoneEmpty(judgeSQLInject(value.toLowerCase()))) {
                    throw new Exception(
                            "参数[" + entry.getKey() + "]含有非法攻击字符[" + judgeSQLInject(value.toLowerCase()) + "],已禁止继续访问！");
                }
                // 跨站xss清理
                clearXss(value);
            }

        }
        return true;
    }

    /**
     * @param str
     * @return
     * @功能描述：防跨站攻击
     */
    protected static boolean jsValidate(String str) {
        // 统一转为小写
        str = str.toLowerCase();
        String badStr = "javascript|vbscript|expression|applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base|onabort|onactivate|"
                + "onafterprint|onafterupdate|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditfocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|"
                + "onblur|onbounce|oncellchange|onchange|onclick|oncontextmenu|oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|ondeactivate|"
                + "ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror|onerrorupdate|onfilterchange|onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|"
                + "onkeyup|onlayoutcomplete|onload|onlosecapture|onmousedown|onmouseenter|onmouseleave|onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|onmovestart|"
                + "onpaste|onpropertychange|onreadystatechange|onreset|onresize|onresizeend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|"
                + "onselectstart|onstart|onstop|onsubmit|onunload";// 过滤掉的sql关键字，可以手动添加
        String[] badStrs = badStr.split("\\|");
        for (int i = 0; i < badStrs.length; i++) {
            if (str.indexOf(badStrs[i]) >= 0) {
                log.info("---" + str.contains(badStrs[i]) + "--str:-" + str + "--[i]-" + badStrs[i]);
                return true;
            }
        }
        return false;
    }

    /**
     * 将parameter的值去除空格后重写回去
     */
    public void modifyParameterValues() {
        Set<String> set = params.keySet();
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            String key = (String) it.next();
            String[] values = params.get(key);
            values[0] = values[0].trim();
            params.put(key, values);
        }
    }

    /**
     * 判断参数是否含有攻击串
     *
     * @param value
     * @return
     */
    public String judgeSQLInject(String value) {
        if (value == null || "".equals(value)) {
            return "";
        }
        /*
         * String xssStr =
         * "and|or|select|update|delete|drop|truncate|%20|=|-|--|;|'|%|+|,|//|/| |\\|!=|(|)"
         * ;
         */
        String xssStr = "<|>|'";
        String[] xssArr = xssStr.split("\\|");
        for (int i = 0; i < xssArr.length; i++) {
            if (value.indexOf(xssArr[i]) > -1) {
                return xssArr[i];
            }
        }
        return "";
    }

    /**
     * 处理跨站xss字符转义
     *
     * @param value
     * @return
     */
    private String clearXss(String value) {
        if (value == null || "".equals(value)) {
            return value;
        }
        value = value.replaceAll("<", "<").replaceAll(">", ">");
        value = value.replaceAll("\\(", "(").replace("\\)", ")");
        value = value.replaceAll("'", "'");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replace("script", "");
        return value;
    }
}
